/*
 * serverLock.cc
 *
 *  Created on: Jun 29, 2011
 *      Author: peckb1
 */

#include "serverLock.h"

ServerLock::ServerLock(char* name, int machineOwner) {
    owningMachine = machineOwner;
    lockName = new char[strlen(name)];
    strcpy(lockName, name);
    lockWaitQueue = new List();
    currentLockState = FREE_STATE;
    currentLockOwner = NULL;
    isDeleted = FALSE;
    isScheduledForDeletion = FALSE;
}


ServerLock::~ServerLock() {
    delete lockWaitQueue;
}

int
ServerLock::Acquire(MailAddress* address) {
    int retVal;

    if(address->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to acquire a lock (%s) owned by Machine %i.\n", address->MachineId(), lockName, owningMachine);
        retVal = 0;
    } else {
        if(!isHeldByCurrentUser(address)) {
            if(currentLockState == FREE_STATE) {
                currentLockState = BUSY_STATE;
                currentLockOwner = address;
                retVal = 1;
            } else {
                lockWaitQueue->Append(address);
                retVal = 2;
            }
        } else {
            printf("ERROR: Machine %i tried to acquire a lock (%s) They already owned by Machine %i.\n", address->MachineId(), lockName, owningMachine);
            retVal = 1;
        }
    }

    return retVal;
}

MailAddress*
ServerLock::Release(MailAddress* address) {
    MailAddress* newOwner = NULL;

    if(address->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to acquire a lock (%s) owned by Machine %i.\n", address->MachineId(), lockName, owningMachine);

    } else if(!isHeldByCurrentUser(address)) {
        printf("ERROR: Machine #%i, box #%i tried to release a lock he did not own.\n", address->MachineId(), address->MailboxNumber());

    } else {
        // happy case - check wait queue
        if(lockWaitQueue->IsEmpty()) {
            currentLockState = FREE_STATE;
            currentLockOwner = NULL;
            newOwner = NULL;
            if(isScheduledForDeletion) {
                isDeleted = TRUE;
                isScheduledForDeletion = FALSE;
            }
        } else {
            newOwner = (MailAddress*)lockWaitQueue->Remove();
            currentLockOwner = newOwner;
        }
    }

    return newOwner;
}

bool
ServerLock::isHeldByCurrentUser(MailAddress* person){
    if(currentLockOwner != NULL) {
        printf("There is an Owner, his stats are %i / %i.\n", currentLockOwner->MachineId(), currentLockOwner->MailboxNumber());
        return (person->MachineId() == currentLockOwner->MachineId() &&
                person->MailboxNumber() == currentLockOwner->MailboxNumber());
    } else {
        printf("There is no owner on this lock!.\n");
        return FALSE;
    }
}

void
ServerLock::DestroyLock(MailAddress* person) {
    if(person->MachineId() != owningMachine) {
        printf("ERROR: Machine %i tried to Destroy a lock (%s) owned by Machine %i.\n", person->MachineId(), lockName, owningMachine);

    } else {
        if(currentLockOwner == NULL) {
            isDeleted = TRUE;
        } else {
            isScheduledForDeletion = TRUE;
        }
    }
}

bool
ServerLock::IsDeleted() {
    return isDeleted;
}

bool
ServerLock::IsScheduledForDeletion() {
    return isScheduledForDeletion;
}

char*
ServerLock::GetName() {
    return lockName;
}
